package com.openmanus.agent.core;

import com.openmanus.agent.memory.Memory;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 智能体执行上下文
 * 包含智能体执行过程中的所有状态信息
 * 
 * @author OpenManus Team
 * @version 1.0.0
 */
@Getter
@Setter
@Builder
public class AgentContext {

    /**
     * 智能体名称
     */
    private String agentName;

    /**
     * 用户请求
     */
    private String request;

    /**
     * 记忆系统
     */
    private Memory memory;

    /**
     * 执行开始时间
     */
    @Builder.Default
    private LocalDateTime startTime = LocalDateTime.now();

    /**
     * 步骤执行结果列表
     */
    @Builder.Default
    private List<StepResult> stepResults = new ArrayList<>();

    /**
     * 上下文变量
     */
    @Builder.Default
    private Map<String, Object> variables = new HashMap<>();

    /**
     * 是否完成标志
     */
    @Builder.Default
    private boolean completed = false;

    /**
     * 最终输出
     */
    private String finalOutput;

    /**
     * 添加步骤执行结果
     * 
     * @param stepResult 步骤结果
     */
    public void addStepResult(StepResult stepResult) {
        stepResults.add(stepResult);
        
        // 如果是终端步骤，标记为完成
        if (stepResult.isTerminal()) {
            this.completed = true;
            this.finalOutput = stepResult.getOutput();
        }
    }

    /**
     * 获取最后一个步骤结果
     * 
     * @return 最后一个步骤结果，如果没有则返回null
     */
    public StepResult getLastStepResult() {
        return stepResults.isEmpty() ? null : stepResults.get(stepResults.size() - 1);
    }

    /**
     * 获取指定索引的步骤结果
     * 
     * @param index 步骤索引
     * @return 步骤结果
     */
    public StepResult getStepResult(int index) {
        if (index >= 0 && index < stepResults.size()) {
            return stepResults.get(index);
        }
        return null;
    }

    /**
     * 获取总步骤数
     * 
     * @return 总步骤数
     */
    public int getTotalSteps() {
        return stepResults.size();
    }

    /**
     * 设置上下文变量
     * 
     * @param key 变量名
     * @param value 变量值
     */
    public void setVariable(String key, Object value) {
        variables.put(key, value);
    }

    /**
     * 获取上下文变量
     * 
     * @param key 变量名
     * @return 变量值
     */
    @SuppressWarnings("unchecked")
    public <T> T getVariable(String key) {
        return (T) variables.get(key);
    }

    /**
     * 获取上下文变量，如果不存在则返回默认值
     * 
     * @param key 变量名
     * @param defaultValue 默认值
     * @return 变量值或默认值
     */
    @SuppressWarnings("unchecked")
    public <T> T getVariable(String key, T defaultValue) {
        return (T) variables.getOrDefault(key, defaultValue);
    }

    /**
     * 检查是否存在指定变量
     * 
     * @param key 变量名
     * @return 是否存在
     */
    public boolean hasVariable(String key) {
        return variables.containsKey(key);
    }

    /**
     * 移除上下文变量
     * 
     * @param key 变量名
     * @return 被移除的变量值
     */
    public Object removeVariable(String key) {
        return variables.remove(key);
    }

    /**
     * 获取执行持续时间（毫秒）
     * 
     * @return 执行持续时间
     */
    public long getDurationMillis() {
        return java.time.Duration.between(startTime, LocalDateTime.now()).toMillis();
    }

    /**
     * 生成执行摘要
     * 
     * @return 执行摘要
     */
    public String generateSummary() {
        StringBuilder summary = new StringBuilder();
        summary.append("智能体: ").append(agentName).append("\n");
        summary.append("请求: ").append(request).append("\n");
        summary.append("开始时间: ").append(startTime).append("\n");
        summary.append("执行步骤数: ").append(stepResults.size()).append("\n");
        summary.append("执行状态: ").append(completed ? "已完成" : "进行中").append("\n");
        summary.append("执行时长: ").append(getDurationMillis()).append("ms\n");
        
        if (completed && finalOutput != null) {
            summary.append("最终输出: ").append(finalOutput).append("\n");
        }
        
        return summary.toString();
    }

    /**
     * 重置上下文状态
     */
    public void reset() {
        stepResults.clear();
        variables.clear();
        completed = false;
        finalOutput = null;
        startTime = LocalDateTime.now();
    }
}
